//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================
/* More subroutines needed by GCC output code on some machines.  */
/* Compile this one with gcc.  */
/* Copyright (C) 1989, 92-98, 1999 Free Software Foundation, Inc.

This file is part of GNU CC.

GNU CC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.

GNU CC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING.  If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.  */

/* As a special exception, if you link this library with other files,
   some of which are compiled with GCC, to produce an executable,
   this library does not by itself cause the resulting executable
   to be covered by the GNU General Public License.
   This exception does not however invalidate any other reasons why
   the executable file might be covered by the GNU General Public License.  */

/* It is incorrect to include config.h here, because this file is being
   compiled for the target, and hence definitions concerning only the host
   do not apply.  */

#include <string.h>
#include <elatypes.h>
#include <eladef.h>
#include "tconfig.h"

// anticly functions below are needed by gcc , their definition is in gcc/libgcc2.c
typedef unsigned int UQItype    __attribute__ ((mode (QI)));
typedef      int SItype __attribute__ ((mode (SI)));
typedef unsigned int USItype    __attribute__ ((mode (SI)));
typedef      int DItype __attribute__ ((mode (DI)));
typedef unsigned int UDItype    __attribute__ ((mode (DI)));

typedef     float SFtype    __attribute__ ((mode (SF)));
typedef     float DFtype    __attribute__ ((mode (DF)));

typedef int word_type __attribute__ ((mode (__word__)));

#define SI_TYPE_SIZE (sizeof (SItype) * BITS_PER_UNIT)

   /* DIstructs are pairs of SItype values in the order determined by
   LIBGCC2_WORDS_BIG_ENDIAN.  */

#if LIBGCC2_WORDS_BIG_ENDIAN
struct DIstruct {SItype high, low;};
#else
struct DIstruct {SItype low, high;};
#endif

/* We need this union to unpack/pack DImode values, since we don't have
   any arithmetic yet.  Incoming DImode parameters are stored into the
   `ll' field, and the unpacked result is read from the struct `s'.  */

typedef union
{
  struct DIstruct s;
  DItype ll;
} DIunion;

#if (defined (L_udivmoddi4) || defined (L_muldi3) || defined (L_udiv_w_sdiv)\
     || defined (L_divdi3) || defined (L_udivdi3) \
     || defined (L_moddi3) || defined (L_umoddi3))

#include "longlong.h"

#endif /* udiv or mul */

extern DItype __fixunssfdi (SFtype a);
extern DItype __fixunsdfdi (DFtype a);
#if LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 96
extern DItype __fixunsxfdi (XFtype a);
#endif
#if LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 128
extern DItype __fixunstfdi (TFtype a);
#endif

#if defined (L_negdi2) || defined (L_divdi3) || defined (L_moddi3)
#if defined (L_divdi3) || defined (L_moddi3)
INLINE
#endif
DItype
__cdecl __negdi2(DItype u)
{
    DIunion w;
    DIunion uu;

    uu.ll = u;

    w.s.low = -uu.s.low;
    w.s.high = -uu.s.high - ((USItype) w.s.low > 0);

    return w.ll;
}
#endif

/* Unless shift functions are defined whith full ANSI prototypes,
   parameter b will be promoted to int if word_type is smaller than an int.  */
#ifdef L_lshrdi3
DItype
__cdecl __lshrdi3(DItype u, word_type b)
{
    DIunion w;
    word_type bm;
    DIunion uu;

    if (b == 0)
        return u;

    uu.ll = u;

    bm = (sizeof (SItype) * BITS_PER_UNIT) - b;
    if (bm <= 0) {
        w.s.high = 0;
        w.s.low = (USItype)uu.s.high >> -bm;
    }
    else {
        USItype carries = (USItype)uu.s.high << bm;
        w.s.high = (USItype)uu.s.high >> b;
        w.s.low = ((USItype)uu.s.low >> b) | carries;
    }

    return w.ll;
}
#endif

#ifdef L_ashldi3
DItype
__cdecl __ashldi3(DItype u, word_type b)
{
    DIunion w;
    word_type bm;
    DIunion uu;

    if (b == 0)
        return u;

    uu.ll = u;

    bm = (sizeof (SItype) * BITS_PER_UNIT) - b;
    if (bm <= 0) {
        w.s.low = 0;
        w.s.high = (USItype)uu.s.low << -bm;
    }
    else {
        USItype carries = (USItype)uu.s.low >> bm;
        w.s.low = (USItype)uu.s.low << b;
        w.s.high = ((USItype)uu.s.high << b) | carries;
    }

    return w.ll;
}
#endif

#ifdef L_ashrdi3
DItype
__cdecl __ashrdi3(DItype u, word_type b)
{
    DIunion w;
    word_type bm;
    DIunion uu;

    if (b == 0)
        return u;

    uu.ll = u;

    bm = (sizeof (SItype) * BITS_PER_UNIT) - b;
    if (bm <= 0) {
        /* w.s.high = 1..1 or 0..0 */
        w.s.high = uu.s.high >> (sizeof (SItype) * BITS_PER_UNIT - 1);
        w.s.low = uu.s.high >> -bm;
    }
    else {
        USItype carries = (USItype)uu.s.high << bm;
        w.s.high = uu.s.high >> b;
        w.s.low = ((USItype)uu.s.low >> b) | carries;
    }

    return w.ll;
}
#endif

#ifdef L_ffsdi2
DItype
__cdecl __ffsdi2(DItype u)
{
    DIunion uu, w;
    uu.ll = u;
    w.s.high = 0;
    w.s.low = ffs (uu.s.low);
    if (w.s.low != 0)
        return w.ll;
    w.s.low = ffs (uu.s.high);
    if (w.s.low != 0) {
        w.s.low += BITS_PER_UNIT * sizeof (SItype);
        return w.ll;
    }
    return w.ll;
}
#endif

#ifdef L_muldi3
DItype
__cdecl __muldi3(DItype u, DItype v)
{
    DIunion w;
    DIunion uu, vv;

    uu.ll = u,
  vv.ll = v;

    w.ll = __umulsidi3 (uu.s.low, vv.s.low);
    w.s.high += ((USItype) uu.s.low * (USItype) vv.s.high
           + (USItype) uu.s.high * (USItype) vv.s.low);

    return w.ll;
}
#endif

#ifdef L_udiv_w_sdiv
#if defined (sdiv_qrnnd)
USItype
__cdecl __udiv_w_sdiv(USItype *rp, USItype a1, USItype a0, USItype d)
{
    USItype q, r;
    USItype c0, c1, b1;

    if ((SItype) d >= 0) {
        if (a1 < d - a1 - (a0 >> (SI_TYPE_SIZE - 1))) {
            /* dividend, divisor, and quotient are nonnegative */
            sdiv_qrnnd (q, r, a1, a0, d);
        }
        else {
            /* Compute c1*2^32 + c0 = a1*2^32 + a0 - 2^31*d */
            sub_ddmmss (c1, c0, a1, a0, d >> 1, d << (SI_TYPE_SIZE - 1));
            /* Divide (c1*2^32 + c0) by d */
            sdiv_qrnnd (q, r, c1, c0, d);
            /* Add 2^31 to quotient */
            q += (USItype) 1 << (SI_TYPE_SIZE - 1);
        }
    }
    else {
        b1 = d >> 1;          /* d/2, between 2^30 and 2^31 - 1 */
        c1 = a1 >> 1;         /* A/2 */
        c0 = (a1 << (SI_TYPE_SIZE - 1)) + (a0 >> 1);

        if (a1 < b1) /* A < 2^32*b1, so A/2 < 2^31*b1 */ {
            sdiv_qrnnd (q, r, c1, c0, b1); /* (A/2) / (d/2) */

            r = 2*r + (a0 & 1);       /* Remainder from A/(2*b1) */
            if ((d & 1) != 0) {
                if (r >= q)
                    r = r - q;
                else if (q - r <= d) {
                    r = r - q + d;
                    q--;
                }
                else {
                    r = r - q + 2*d;
                    q -= 2;
                }
            }
        }
        else if (c1 < b1) /* So 2^31 <= (A/2)/b1 < 2^32 */ {
            c1 = (b1 - 1) - c1;
            c0 = ~c0;         /* logical NOT */

            sdiv_qrnnd (q, r, c1, c0, b1); /* (A/2) / (d/2) */

            q = ~q;           /* (A/2)/b1 */
            r = (b1 - 1) - r;

            r = 2*r + (a0 & 1);       /* A/(2*b1) */

            if ((d & 1) != 0) {
                if (r >= q)
                    r = r - q;
                else if (q - r <= d) {
                    r = r - q + d;
                    q--;
                }
                else {
                    r = r - q + 2*d;
                    q -= 2;
                }
            }
        }
        else /* Implies c1 = b1 */ {               /* Hence a1 = d - 1 = 2*b1 - 1 */
            if (a0 >= -d) {
                q = -1;
                r = a0 + d;
            }
            else {
                q = -2;
                r = a0 + 2*d;
            }
        }
    }

    *rp = r;
    return q;
}
#else
/* If sdiv_qrnnd doesn't exist, define dummy __udiv_w_sdiv.  */
USItype
__cdecl __udiv_w_sdiv(USItype *rp __attribute__ ((__unused__)),
    USItype a1 __attribute__ ((__unused__)),
    USItype a0 __attribute__ ((__unused__)),
    USItype d __attribute__ ((__unused__)))
{
    return 0;
}
#endif
#endif

#if (defined (L_udivdi3) || defined (L_divdi3) || \
     defined (L_umoddi3) || defined (L_moddi3))
#define L_udivmoddi4
#endif

#ifdef L_udivmoddi4
static const UQItype __clz_tab[] =
{
  0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
  6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
  7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
  7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
  8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
  8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
  8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
  8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
};

#if (defined (L_udivdi3) || defined (L_divdi3) || \
     defined (L_umoddi3) || defined (L_moddi3))
INLINE
#endif
UDItype
__cdecl __udivmoddi4(UDItype n, UDItype d, UDItype *rp)
{
    DIunion ww;
    DIunion nn, dd;
    DIunion rr;
    USItype d0, d1, n0, n1, n2;
    USItype q0, q1;
    USItype b, bm;

    nn.ll = n;
    dd.ll = d;

    d0 = dd.s.low;
    d1 = dd.s.high;
    n0 = nn.s.low;
    n1 = nn.s.high;

#if !UDIV_NEEDS_NORMALIZATION
    if (d1 == 0) {
        if (d0 > n1) {
            /* 0q = nn / 0D */

            udiv_qrnnd (q0, n0, n1, n0, d0);
            q1 = 0;

            /* Remainder in n0.  */
        }
        else {
            /* qq = NN / 0d */

            if (d0 == 0)
                d0 = 1 / d0;    /* Divide intentionally by zero.  */

            udiv_qrnnd (q1, n1, 0, n1, d0);
            udiv_qrnnd (q0, n0, n1, n0, d0);

            /* Remainder in n0.  */
        }

        if (rp != 0) {
            rr.s.low = n0;
            rr.s.high = 0;
            *rp = rr.ll;
        }
    }

#else /* UDIV_NEEDS_NORMALIZATION */

    /* UDIV_NEEDS_NORMALIZATION */

    if (d1 == 0) {
        if (d0 > n1) {
            /* 0q = nn / 0D */

            count_leading_zeros (bm, d0);

            if (bm != 0) {
                /* Normalize, i.e. make the most significant bit of the
         denominator set.  */

                d0 = d0 << bm;
                n1 = (n1 << bm) | (n0 >> (SI_TYPE_SIZE - bm));
                n0 = n0 << bm;
            }

            udiv_qrnnd (q0, n0, n1, n0, d0);
            q1 = 0;

            /* Remainder in n0 >> bm.  */
        }
        else {
            /* qq = NN / 0d */

            if (d0 == 0)
                d0 = 1 / d0;    /* Divide intentionally by zero.  */

            count_leading_zeros (bm, d0);

            if (bm == 0) {
                /* From (n1 >= d0) /\ (the most significant bit of d0 is set),
         conclude (the most significant bit of n1 is set) /\ (the
         leading quotient digit q1 = 1).

         This special case is necessary, not an optimization.
         (Shifts counts of SI_TYPE_SIZE are undefined.)  */

                n1 -= d0;
                q1 = 1;
            }
            else {
                /* Normalize.  */

                b = SI_TYPE_SIZE - bm;

                d0 = d0 << bm;
                n2 = n1 >> b;
                n1 = (n1 << bm) | (n0 >> b);
                n0 = n0 << bm;

                udiv_qrnnd (q1, n1, n2, n1, d0);
            }

            /* n1 != d0...  */

            udiv_qrnnd (q0, n0, n1, n0, d0);

            /* Remainder in n0 >> bm.  */
        }

        if (rp != 0) {
            rr.s.low = n0 >> bm;
            rr.s.high = 0;
            *rp = rr.ll;
        }
    }
#endif /* UDIV_NEEDS_NORMALIZATION */

    else
    {
      if (d1 > n1)
    {
      /* 00 = nn / DD */

      q0 = 0;
      q1 = 0;

      /* Remainder in n1n0.  */
      if (rp != 0)
        {
          rr.s.low = n0;
          rr.s.high = n1;
          *rp = rr.ll;
        }
    }
      else
    {
      /* 0q = NN / dd */

      count_leading_zeros (bm, d1);
      if (bm == 0)
        {
          /* From (n1 >= d1) /\ (the most significant bit of d1 is set),
         conclude (the most significant bit of n1 is set) /\ (the
         quotient digit q0 = 0 or 1).

         This special case is necessary, not an optimization.  */

          /* The condition on the next line takes advantage of that
         n1 >= d1 (true due to program flow).  */
          if (n1 > d1 || n0 >= d0)
        {
          q0 = 1;
          sub_ddmmss (n1, n0, n1, n0, d1, d0);
        }
          else
        q0 = 0;

          q1 = 0;

          if (rp != 0)
        {
          rr.s.low = n0;
          rr.s.high = n1;
          *rp = rr.ll;
        }
        }
      else
        {
          USItype m1, m0;
          /* Normalize.  */

          b = SI_TYPE_SIZE - bm;

          d1 = (d1 << bm) | (d0 >> b);
          d0 = d0 << bm;
          n2 = n1 >> b;
          n1 = (n1 << bm) | (n0 >> b);
          n0 = n0 << bm;

          udiv_qrnnd (q0, n1, n2, n1, d1);
          umul_ppmm (m1, m0, q0, d0);

          if (m1 > n1 || (m1 == n1 && m0 > n0))
        {
          q0--;
          sub_ddmmss (m1, m0, m1, m0, d1, d0);
        }

          q1 = 0;

          /* Remainder in (n1n0 - m1m0) >> bm.  */
          if (rp != 0)
        {
          sub_ddmmss (n1, n0, n1, n0, m1, m0);
          rr.s.low = (n1 << b) | (n0 >> bm);
          rr.s.high = n1 >> bm;
          *rp = rr.ll;
        }
        }
    }
    }

    ww.s.low = q0;
    ww.s.high = q1;
    return ww.ll;
}
#endif

#ifdef L_divdi3

DItype
__cdecl __divdi3(DItype u, DItype v)
{
    word_type c = 0;
    DIunion uu, vv;
    DItype w;

    uu.ll = u;
    vv.ll = v;

    if (uu.s.high < 0)
        c = ~c,
    uu.ll = __negdi2 (uu.ll);
    if (vv.s.high < 0)
        c = ~c,
    vv.ll = __negdi2 (vv.ll);

    w = __udivmoddi4 (uu.ll, vv.ll, (UDItype *) 0);
    if (c)
        w = __negdi2 (w);

    return w;
}
#endif

#ifdef L_moddi3
DItype
__cdecl __moddi3(DItype u, DItype v)
{
    word_type c = 0;
    DIunion uu, vv;
    UDItype w;

    uu.ll = u;
    vv.ll = v;

    if (uu.s.high < 0)
        c = ~c,
    uu.ll = __negdi2 (uu.ll);
    if (vv.s.high < 0)
        vv.ll = __negdi2 (vv.ll);

    (void) __udivmoddi4 (uu.ll, vv.ll, &w);
    if (c)
        w = __negdi2 (w);

    return w;
}
#endif

#ifdef L_umoddi3
UDItype
__cdecl __umoddi3(UDItype u, UDItype v)
{
    UDItype w;

    (void) __udivmoddi4 (u, v, &w);

    return w;
}
#endif

#ifdef L_udivdi3
UDItype
__cdecl __udivdi3(UDItype n, UDItype d)
{
    return __udivmoddi4 (n, d, (UDItype *) 0);
}
#endif

#ifdef L_cmpdi2
word_type
__cdecl __cmpdi2(DItype a, DItype b)
{
    DIunion au, bu;

    au.ll = a, bu.ll = b;

    if (au.s.high < bu.s.high)
        return 0;
    else if (au.s.high > bu.s.high)
        return 2;
    if ((USItype) au.s.low < (USItype) bu.s.low)
        return 0;
    else if ((USItype) au.s.low > (USItype) bu.s.low)
        return 2;
    return 1;
}
#endif

#ifdef L_ucmpdi2
word_type
__cdecl __ucmpdi2(DItype a, DItype b)
{
    DIunion au, bu;

    au.ll = a, bu.ll = b;

    if ((USItype) au.s.high < (USItype) bu.s.high)
        return 0;
    else if ((USItype) au.s.high > (USItype) bu.s.high)
        return 2;
    if ((USItype) au.s.low < (USItype) bu.s.low)
        return 0;
    else if ((USItype) au.s.low > (USItype) bu.s.low)
        return 2;
    return 1;
}
#endif

///////////////////////////////////////////////
extern void __cdecl __sjthrow (void);
extern void __cdecl __default_terminate (void);

void __cdecl (*__terminate_func)() = __default_terminate;

void __cdecl __default_terminate()
{
    DebugBreak();
}

void __cdecl __terminate()
{
    (*__terminate_func)();
}

#if 0
void __cdecl __sjthrow()
{
    abort();
}
#endif
//////////////////
struct eh_context
{
    void *handler_label;
    void **dynamic_handler_chain;
  /* This is language dependent part of the eh context. */
    void *info;
  /* This is used to remember where we threw for re-throws */
    void *table_index;  /* address of exception table entry to rethrow from */
};
/* Pointer to function to return EH context. */

static struct eh_context * __cdecl eh_context_initialize();
static struct eh_context * __cdecl eh_context_static();
static struct eh_context * __cdecl (*get_eh_context)() = &eh_context_initialize;

static struct eh_context * __cdecl eh_context_initialize()
{
    /* Use static version of EH context. */
    get_eh_context = &eh_context_static;
    return (*get_eh_context) ();
}

/* Return a static EH context. */
static struct eh_context * __cdecl eh_context_static()
{
    static struct eh_context eh;
    static int initialized;
    static void *top_elt[10];

    if (!initialized) {
        initialized = 1;
        memset (&eh, 0, sizeof eh);
        eh.dynamic_handler_chain = top_elt;
    }
    return &eh;
}

void * __cdecl __get_eh_context()
{
    return (void *) (*get_eh_context) ();
}
void ** __cdecl __get_eh_info()
{
    struct eh_context *eh = (*get_eh_context) ();
    return &eh->info;
}
